﻿using System;
using System.Data.Common;
using System.Linq;
using System.Linq.Expressions;

namespace DbService
{
    using System.Data.Entity;
    using System.Data.Entity.Validation;
    using EntityFramework.Extensions;
    using System.Data.Entity.Infrastructure;
    using DbService.Repository;
    using System.Collections.Generic;

    public class RepositoryAchieve<T> : IRepository<T> where T : class
    {
        private DbContext Context;

        public RepositoryAchieve(DbContext _DbContext)
        {
            Context = _DbContext;
        }

        /// <summary>
        /// insert
        /// </summary>
        /// <param name="_Entity"></param>
        public void Insert(T _Entity)
        {
            this.Context.Set<T>().Add(_Entity);
            this.Save();
        }

        /// <summary>
        /// insert
        /// </summary>
        /// <param name="_Entity"></param>
        public void InsertBatch(T[] _Entity)
        {
            this.Context.Set<T>().AddRange(_Entity);
            this.Save();
        }

        /// <summary>
        /// update
        /// </summary>
        /// <param name="_Entity"></param>
        /// <param name="_Where"></param>
        public void Update(Expression<Func<T, T>> _Entity, Expression<Func<T, bool>> _Where)
        {
            this.Context.Set<T>().Where(_Where).Update(_Entity);
            this.Save();
        }

        /// <summary>
        /// Update
        /// </summary>
        /// <param name="_Entity"></param>
        public void UpdateById(T _Entity)
        {
            var list = new List<MemberBinding>();
            var _KeyName = string.Empty;
            object _KeyValue = null;

            //创建一个 Expression<Func<T, T>> 表达式
            var _Set_Parameter = Expression.Parameter(typeof(T), "orig");
            var _Tuple = RepositoryHelper.GetEntityKey<T>(_Entity, (item) =>
            {
                list.Add(Expression.Bind(item, Expression.Constant(item.GetValue(_Entity), item.PropertyType)));
            });
            _KeyName = _Tuple.Item1;
            _KeyValue = _Tuple.Item2;
            var _Set_Body = Expression.MemberInit(Expression.New(typeof(T)), list);

            var _Set = Expression.Lambda<Func<T, T>>(_Set_Body, _Set_Parameter);
            var _Where = RepositoryHelper.WhereById<T>(_KeyName, _KeyValue);
            this.Update(_Set, _Where);
        }

        /// <summary>
        /// delete
        /// </summary>
        /// <param name="_Where"></param>
        public void Delete(Expression<Func<T, bool>> _Where)
        {
            Context.Set<T>().Where(_Where).Delete();
            this.Save();
        }

        /// <summary>
        /// delete
        /// </summary>
        /// <param name="_Entity"></param>
        public void Delete(T _Entity)
        {
            Context.Set<T>().Remove(_Entity);
            this.Save();
        }

        /// <summary>
        /// DeleteById
        /// </summary>
        /// <param name="Id"></param>
        public void DeleteById(object Id)
        {
            var _Entity = RepositoryHelper.CreateInstance<T>();
            var _Tuple = RepositoryHelper.GetEntityKey<T>(_Entity);
            var _Where = RepositoryHelper.WhereById<T>(_Tuple.Item1, Id);
            this.Delete(_Where);
        }

        /// <summary>
        /// find Entity
        /// </summary>
        /// <param name="_Where"></param>
        /// <returns></returns>
        public T FindSingle(Expression<Func<T, bool>> _Where)
        {
            var _Entity = Context.Set<T>().AsNoTracking().FirstOrDefault(_Where);
            if (_Entity == null) _Entity = RepositoryHelper.CreateInstance<T>();
            return _Entity;
        }

        /// <summary>
        /// find Entity
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        public T FindSingleById(object Id)
        {
            var _Entity = RepositoryHelper.CreateInstance<T>();
            var _Tuple = RepositoryHelper.GetEntityKey<T>(_Entity);
            var _Where = RepositoryHelper.WhereById<T>(_Tuple.Item1, Id);
            return this.FindSingle(_Where);
        }

        /// <summary>
        /// IsExist
        /// </summary>
        /// <param name="_Where"></param>
        /// <returns></returns>
        public bool IsExist(Expression<Func<T, bool>> _Where)
        {
            return Context.Set<T>().Any(_Where);
        }

        /// <summary>
        /// GetCount
        /// </summary>
        /// <param name="_Where"></param>
        /// <returns></returns>
        public int GetCount(Expression<Func<T, bool>> _Where = null)
        {
            return Filter(_Where).Count();
        }

        /// <summary>
        /// IQueryable<T>
        /// </summary>
        /// <param name="_Where"></param>
        /// <returns></returns>
        public IQueryable<T> Find(Expression<Func<T, bool>> _Where = null)
        {
            return Filter(_Where);
        }




        public int Save()
        {
            return Context.SaveChanges();
        }

        public void Commit(Action _Action)
        {
            var _BeginTransaction = Context.Database.BeginTransaction();

            try
            {
                //调用委托
                _Action?.Invoke();

                _BeginTransaction.Commit();
            }
            catch (Exception ex)
            {
                _BeginTransaction.Rollback();
                throw ex;
            }
        }

        private IQueryable<T> Filter(Expression<Func<T, bool>> exp)
        {
            var dbSet = Context.Set<T>().AsNoTracking().AsQueryable();
            if (exp != null)
                dbSet = dbSet.Where(exp);
            return dbSet;
        }

    }
}
